﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using CodePlex.TfsPluginSuite.Configuration;
using CodePlex.TfsPluginSuite.Helper;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.Framework.Server;
using Microsoft.TeamFoundation.VersionControl.Server;

namespace CodePlex.TfsPluginSuite.Overrides
{
    public class PatternBypassOverride : ISubscriber
    {
        public string Name
        {
            get { return typeof(PatternBypassOverride).FullName; }
        }

        public SubscriberPriority Priority
        {
            get { return SubscriberPriority.High; }
        }

        public Type[] SubscribedTypes()
        {
            return new Type[1] { typeof(CheckinNotification) };
        }

        public EventNotificationStatus ProcessEvent(TeamFoundationRequestContext requestContext,
            NotificationType notificationType,
            object notificationEventArgs,
            out int statusCode,
            out string statusMessage,
            out ExceptionPropertyCollection properties)
        {
            properties = new ExceptionPropertyCollection();
            statusMessage = String.Empty;
            statusCode = 0;

            var config = TfsPluginSuiteConfigurationManager.Section.PatternBypassOverride;

            // don't run this policy if it's disabled in the config file
            if (!config.Enabled)
            {
                return EventNotificationStatus.ActionPermitted;
            }

            // If this is a check-in notification and is a decision point
            if (notificationEventArgs is CheckinNotification && notificationType == NotificationType.DecisionPoint)
            {
                CheckinNotification notification = notificationEventArgs as CheckinNotification;

                //get submitted items out of the loops to save some time.
                var submittedItems = notification.GetSubmittedItems(requestContext);

                using (var tfsHelper = new TfsHelper(requestContext, notification))
                {
                    // iterate through each override pattern
                    foreach (PatternBypassOverrideConfigElement bypassConfig in config)
                    {
                        //if all paths match, its not so common, so now we will go out and retrieve the details of the pending changes from the server
                        if (submittedItems.All(item => Regex.IsMatch(item, bypassConfig.PathRegex)))
                        {
                            //get our enums for the allowed bypass types
                            var stringTypes = bypassConfig.ChangeType.Split(',');
                            var bypassTypes = stringTypes.Select<string, ChangeType>(a => (ChangeType)Enum.Parse(typeof(ChangeType), a));

                            bool allTypesMatch = true;

                            // getting pendingchanges instead of using SubmittedItems from RequestContext because we need to know the changetype
                            foreach (PendingChange change in tfsHelper.GetPendingChanges())
                            {
                                var changeType = (ChangeType)change.ChangeEx;

                                //if there are not any allowed types in this pending change, then all types do NOT match!
                                if (!bypassTypes.Any(bypassType => changeType.HasFlag(bypassType)))
                                {
                                    allTypesMatch = false;
                                }
                            }

                            // if all types match, free ride!
                            if (allTypesMatch)
                            {
                                return EventNotificationStatus.ActionApproved;
                            }
                        }
                    }
                }
            }
            return EventNotificationStatus.ActionPermitted;
        }
    }
}
